package service

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"github.com/google/uuid"
	"github.com/spf13/viper"
	"io"
	"log"
	"net/http"
	"riceguess_backend/internal/domain"
	"riceguess_backend/internal/repository"
	"strconv"
)

type AIService interface {
	GetTitle(ctx context.Context) (domain.Answer, error)
	SendQuestion(ctx context.Context, id string, question string) (string, error)
	ReduceTruth(ctx context.Context, id string, guess string) (bool, error)
}

type DefaultAIService struct {
	repo repository.AnswerRepository
}

func NewDefaultAIService(repo repository.AnswerRepository) AIService {
	return &DefaultAIService{
		repo: repo,
	}
}

// GetTitle 获取题面信息
func (svc *DefaultAIService) GetTitle(ctx context.Context) (domain.Answer, error) {
	// 创建 HTTP 客户端
	client := &http.Client{}
	// 构建请求体
	requestBody := RequestBody{
		// 模型列表：https://help.aliyun.com/zh/model-studio/getting-started/models
		Model: "qwen-plus",
		Messages: []Message{
			{
				Role:    "system",
				Content: "你现在扮演的是一个《猜到你了》游戏的主持人，这个游戏类似于海龟汤，你现在需要给出故事的汤面，请严格按照如下固定JSON格式输出：{\n\t\t\"title\": \"深夜，男子听到隔壁传来弹珠落地的声音，第二天报警。请问发生了什么？\",\n\t\t\"truth\": \"弹珠声会出现的地方是使用了预制的预应力混凝土多孔板做楼面和屋面的建筑\",\n\t}其中你需要做的就是随机找一个汤面替换title，以及对应的真相truth",
			},
		},
	}
	jsonData, err := json.Marshal(requestBody)
	if err != nil {
		log.Fatal(err)
	}
	// 创建 POST 请求
	req, err := http.NewRequest(http.MethodPost, "https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions", bytes.NewBuffer(jsonData))
	if err != nil {
		log.Fatal(err)
	}
	// 设置请求头
	apiKey := viper.GetString("aliyun.apikey")
	req.Header.Set("Authorization", "Bearer "+apiKey)
	req.Header.Set("Content-Type", "application/json")
	// 发送请求
	resp, err := client.Do(req)
	if err != nil {
		log.Fatal(err)
	}
	defer resp.Body.Close()
	// 读取响应体
	bodyText, err := io.ReadAll(resp.Body)
	if err != nil {
		// TODO 记录日志
		return domain.Answer{}, err
	}
	// 反序列化
	var response Response
	err = json.Unmarshal(bodyText, &response)
	if err != nil {
		return domain.Answer{}, err
	}
	// 打印响应内容
	var answer domain.Answer
	err = json.Unmarshal([]byte(response.Choices[0].Message.Content), &answer)
	if err != nil {
		return domain.Answer{}, err
	}
	fmt.Println("响应:", answer)
	// 随机生成id
	answer.Id = uuid.New().String()
	// 将答案缓存到redis中
	err = svc.repo.Store(ctx, answer)
	if err != nil {
		return domain.Answer{}, err
	}
	return domain.Answer{
		Id:    answer.Id,
		Title: fmt.Sprintf("欢迎来到是否与此无关游戏！【汤面】%s", answer.Title),
	}, nil
}

// SendQuestion 询问问题
func (svc *DefaultAIService) SendQuestion(ctx context.Context, id string, question string) (string, error) {
	// 查询id对应的答案
	answer, err := svc.repo.Get(ctx, id)
	// 创建 HTTP 客户端
	client := &http.Client{}
	// 构建请求体
	requestBody := RequestBody{
		// 模型列表：https://help.aliyun.com/zh/model-studio/getting-started/models
		Model: "qwen-plus",
		Messages: []Message{
			{
				Role:    "user",
				Content: fmt.Sprintf("你现在扮演的是一个《猜到你了》游戏的主持人，这个游戏类似于海龟汤，这是你原先给出的故事汤面:%s, 你原先给出的真相是:%s，用户提的问题是:%s，你现在需要根据用户的问题和题面进行回答，如果用户问的问题跟本题真相毫不相干（跑偏了）就回复与此无关；如果用户问的问题与真相符合就回复是；如果如果用户问的问题与真相不符合就回复否，请确保你本次输出内容只有三者中的一个，不要输出多余内容!", answer.Title, answer.Truth, question),
			},
		},
	}
	jsonData, err := json.Marshal(requestBody)
	if err != nil {
		log.Fatal(err)
	}
	// 创建 POST 请求
	req, err := http.NewRequest(http.MethodPost, "https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions", bytes.NewBuffer(jsonData))
	if err != nil {
		log.Fatal(err)
	}
	// 设置请求头
	apiKey := viper.GetString("aliyun.apikey")
	req.Header.Set("Authorization", "Bearer "+apiKey)
	req.Header.Set("Content-Type", "application/json")
	// 发送请求
	resp, err := client.Do(req)
	if err != nil {
		log.Fatal(err)
	}
	defer resp.Body.Close()
	// 读取响应体
	bodyText, err := io.ReadAll(resp.Body)
	if err != nil {
		// TODO 记录日志
		return "", err
	}
	// 反序列化
	var response Response
	err = json.Unmarshal(bodyText, &response)
	if err != nil {
		return "", err
	}
	// 打印响应内容
	fmt.Println("响应:", response.Choices[0].Message.Content)
	return response.Choices[0].Message.Content, nil
}

// ReduceTruth 还原真相
func (svc *DefaultAIService) ReduceTruth(ctx context.Context, id string, guess string) (bool, error) {
	// 查询id对应的答案
	answer, err := svc.repo.Get(ctx, id)
	// 创建 HTTP 客户端
	client := &http.Client{}
	// 构建请求体
	requestBody := RequestBody{
		// 模型列表：https://help.aliyun.com/zh/model-studio/getting-started/models
		Model: "qwen-plus",
		Messages: []Message{
			{
				Role:    "user",
				Content: fmt.Sprintf("你现在扮演的是一个《猜到你了》游戏的主持人，这个游戏类似于海龟汤，这是你原先给出的故事汤面:%s, 你原先给出的真相是:%s，用户猜测的真相是:%s，你现在需要根据用户猜测内容和题面进行回答，如果用户猜测与真相大致相符就返回true，否则返回false，请确保你本次输出内容只有二者中的一个，不要输出多余内容!", answer.Title, answer.Truth, guess),
			},
		},
	}
	jsonData, err := json.Marshal(requestBody)
	if err != nil {
		log.Fatal(err)
	}
	// 创建 POST 请求
	req, err := http.NewRequest(http.MethodPost, "https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions", bytes.NewBuffer(jsonData))
	if err != nil {
		log.Fatal(err)
	}
	// 设置请求头
	apiKey := viper.GetString("aliyun.apikey")
	req.Header.Set("Authorization", "Bearer "+apiKey)
	req.Header.Set("Content-Type", "application/json")
	// 发送请求
	resp, err := client.Do(req)
	if err != nil {
		log.Fatal(err)
	}
	defer resp.Body.Close()
	// 读取响应体
	bodyText, err := io.ReadAll(resp.Body)
	if err != nil {
		// TODO 记录日志
		return false, err
	}
	// 反序列化
	var response Response
	err = json.Unmarshal(bodyText, &response)
	if err != nil {
		return false, err
	}
	// 打印响应内容
	fmt.Println("响应:", response.Choices[0].Message.Content)
	parseBool, err := strconv.ParseBool(response.Choices[0].Message.Content)
	if err != nil {
		return false, err
	}
	return parseBool, nil
}

type Message struct {
	Role    string `json:"role"`
	Content string `json:"content"`
}
type RequestBody struct {
	Model    string    `json:"model"`
	Messages []Message `json:"messages"`
}

type Response struct {
	Choices []Choice `json:"choices"`
}

type Choice struct {
	Message Message `json:"message"`
}
